home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / www / src / midaswww-1.0 / midaswww.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-16  |  23.9 KB  |  1,071 lines

  1. /*
  2.  *  These are the WWW - Midas Interface routines
  3.  */ 
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <netdb.h>
  8. #include <stdio.h>
  9.  
  10. #ifdef VAX
  11. #define CADDR_T
  12. #define __TYPES_LOADED
  13. #include ctype
  14. #endif
  15.  
  16. #include <Mrm/MrmAppl.h>                        /* Motif Toolkit and MRM */
  17. #include "midas.h"
  18. #include "SGMLHyper.h"
  19. #include "SGMLAnchorText.h"
  20. #include "SGMLCompositeText.h"
  21. #include <string.h>
  22.  
  23.  
  24. #ifndef VAX
  25. #define socket_read(a,b,c) read(a,b,c)
  26. #define socket_write(a,b,c) write(a,b,c)
  27. #define socket_close(a) close(a)
  28. #endif
  29.  
  30. /*
  31.  *  Structures
  32.  */
  33.  
  34. #define HASHSIZE 337
  35. #define DEADNODE ((WWWNode *) -1)
  36.  
  37. typedef struct  {
  38.  
  39.   XrmQuark protocol;
  40.   XrmQuark node;
  41.   int      port;
  42.   XrmQuark file;      
  43.   XrmQuark anchor; 
  44.   XrmQuark keyword;
  45.  
  46. } WWWFile;  
  47.  
  48. static WWWFile WWWFileDefault;
  49.  
  50. struct _WWWNode {
  51.  
  52.   struct     _WWWNode *hashclash; 
  53.   
  54.   struct     _WWWNode *parent;
  55.   struct     _WWWNode *next;
  56.   struct     _WWWNode *prev;
  57.   struct     _WWWNode *up;
  58.   struct     _WWWNode *down;
  59.   struct     _WWWNode *chain;
  60.  
  61.   WWWFile    *file;
  62.   Boolean    visited;
  63.  
  64.   WidgetList widgets;  /* current list of widgets corresponding to this node */
  65.   int num_widgets;
  66.   int alloc_widgets;
  67.  
  68. };
  69. typedef struct _WWWNode WWWNode;   
  70.  
  71. struct _WWWLink {
  72.     
  73.   WWWNode *from;
  74.   WWWNode *to;    
  75.  
  76. };
  77. typedef struct _WWWLink WWWLink;   
  78.  
  79. static WWWNode *HashTable[HASHSIZE];
  80. static WWWFile *WWWGateway; 
  81. static WWWNode *WWWToLink = NULL;
  82. static WWWNode *WWWFromLink = DEADNODE;
  83.  
  84. /* Ugly static variable that keeps track of where we are in processing a document */
  85.  
  86. static int nextid;
  87. static WWWNode *lastnode;
  88. static WWWNode *parent;
  89.  
  90. static XrmQuark localProtocol;
  91. static XrmQuark httpProtocol;
  92.  
  93. typedef struct {
  94.  
  95.   int   socket;
  96.   int   nleft;
  97.   char  *next;
  98.   
  99. } DataSource;  
  100.  
  101. /*
  102.  * Application resources
  103.  * 
  104.  */
  105.  
  106. #define WWWINHERIT_FONT    NULL
  107. #define WWWINHERIT_UNDERLINE -999
  108. #define WWWINHERIT_OUTLINE 2
  109. #define WWWINHERIT_UNDERLINEHEIGHT 999
  110. #define WWWINHERIT_COLOR NULL
  111.  
  112. #define WWWNvisitedFont            "visitedFont"
  113. #define WWWNvisitedColor           "visitedColor"
  114. #define WWWNvisitedUnderline       "visitedUnderline"
  115. #define WWWNvisitedOutline         "visitedOutline"
  116. #define WWWNvisitedUnderlineHeight "visitedUnderlineHeight"
  117.  
  118. #define WWWNdefaultHTTPPort        "defaultHTTPPort"
  119. #define WWWCPort                   "Port"
  120. #define WWWNhelp                   "help"
  121. #define WWWCHelp                   "Help" 
  122.  
  123. typedef struct {
  124.  
  125.     Pixel               color;
  126.     Boolean             outline;                 
  127.     int                 underline;
  128.     Dimension           underline_height;
  129.     XFontStruct         *font;
  130.  
  131.     int                 default_HTTP_port;
  132.     String              help; 
  133.  
  134. } WWWResources;
  135.  
  136. static WWWResources appResources;
  137.  
  138. #define Offset(field) XtOffsetOf(WWWResources,field) 
  139.  
  140. static XtResource resources[] = { 
  141.  
  142.     {WWWNvisitedFont, SGMLCFont, XtRFontStruct, sizeof (XFontStruct *),
  143.     Offset(font), XtRString, WWWINHERIT_FONT},
  144.  
  145.     {WWWNvisitedColor, SGMLCColor, XtRPixel, sizeof (Pixel),
  146.     Offset(color),XtRString, WWWINHERIT_COLOR},
  147.  
  148.     {WWWNvisitedOutline,SGMLCOutline,XtRBoolean,sizeof(Boolean),
  149.     Offset(outline),XtRImmediate,(XtPointer) WWWINHERIT_OUTLINE},
  150.  
  151.     {WWWNvisitedUnderline,SGMLCUnderline,XtRInt,sizeof(int),
  152.     Offset(underline),XtRImmediate,(XtPointer) WWWINHERIT_UNDERLINE},
  153.  
  154.     {WWWNvisitedUnderlineHeight, SGMLCUnderlineHeight, XtRDimension, sizeof(Dimension),
  155.     Offset(underline_height),XtRImmediate,(XtPointer) WWWINHERIT_UNDERLINEHEIGHT},
  156.  
  157.     {WWWNdefaultHTTPPort, WWWCPort, XtRInt, sizeof(int),
  158.     Offset(default_HTTP_port),XtRImmediate,(XtPointer) 80},
  159.  
  160.     {WWWNhelp, WWWCHelp, XtRString, sizeof(char *),
  161.     Offset(help),XtRString,(XtPointer) "http://slacvx.slac.stanford.edu:80/MidasWWW/v10/"},
  162.  
  163. };    
  164.  
  165. #undef Offset
  166.  
  167. /*
  168.  * Calculates a hash id from a WWWFile
  169.  * -----------------------------------
  170.  */
  171. static int WWWHash(file)
  172. WWWFile *file;
  173. {
  174.    return ((int) file->protocol + 
  175.            (int) file->node     + 
  176.            (int) file->file     + 
  177.            (int) file->anchor   + 
  178.            file->port           ) % HASHSIZE; 
  179. }
  180. static void WWWAsciiFile(buffer,pfile)
  181. char *buffer;
  182. WWWFile *pfile;
  183. {
  184.   sprintf(buffer,"%s:",XrmQuarkToString(pfile->protocol));
  185.   buffer += strlen(buffer);
  186.   
  187.   if (pfile->node)
  188.     {
  189.       sprintf(buffer,"//%s",XrmQuarkToString(pfile->node));
  190.       buffer += strlen(buffer);
  191.     }  
  192.  
  193.   if (pfile->port) 
  194.     {  
  195.       sprintf(buffer,":%d",pfile->port);
  196.       buffer += strlen(buffer);
  197.     }
  198.      
  199.   sprintf(buffer,"%s",XrmQuarkToString(pfile->file));
  200.   buffer += strlen(buffer);
  201.  
  202.   if (pfile->anchor)
  203.     {
  204.       sprintf(buffer,"#%s",XrmQuarkToString(pfile->anchor));
  205.       buffer += strlen(buffer);
  206.     }
  207.  
  208. }
  209. /*
  210.  *  Dump the hash table
  211.  *  -------------------
  212.  */
  213. static void WWWHashDump()
  214. {
  215.   int i;
  216.   for (i=0; i<HASHSIZE; i++)
  217.     {
  218.       WWWNode *a = HashTable[i]; 
  219.       for (; a != NULL; a = a->hashclash) 
  220.         {
  221.           WWWFile *pfile = a->file; 
  222.           WWWNode *a = HashTable[i]; 
  223.           char p[256];
  224.  
  225.           WWWAsciiFile(p,pfile);
  226.           
  227.           printf("(%d,%d,%d,%d,%d,%d) %s\n",pfile->protocol,pfile->node,pfile->port,
  228.                                             pfile->file,pfile->anchor,pfile->keyword,p);
  229.          }                                   
  230.      }
  231. }
  232. /*
  233.  * Called to mark an anchor as visited
  234.  */
  235. static void WWWBeenThere(w)
  236. Widget w;
  237. {
  238.   Arg arglist[10];
  239.   int n=0;
  240.   
  241.   if (appResources.color!=WWWINHERIT_COLOR) 
  242.   {
  243.     XtSetArg(arglist[n],SGMLNsensitiveColor,appResources.color); n++;
  244.   }
  245.   if (appResources.font!=WWWINHERIT_FONT) 
  246.   {
  247.     XtSetArg(arglist[n],SGMLNsensitiveFont,appResources.font ); n++;
  248.   }
  249.   if (appResources.outline!=WWWINHERIT_OUTLINE) 
  250.   {
  251.     XtSetArg(arglist[n],SGMLNsensitiveOutline,appResources.outline); n++;
  252.   }
  253.   if (appResources.underline!=WWWINHERIT_UNDERLINE) 
  254.   {
  255.     XtSetArg(arglist[n],SGMLNsensitiveUnderline,appResources.underline); n++;
  256.   }
  257.   if (appResources.underline_height!=WWWINHERIT_UNDERLINEHEIGHT) 
  258.   {
  259.     XtSetArg(arglist[n],SGMLNsensitiveUnderlineHeight,appResources.underline_height); n++;
  260.   }
  261.   if (n) XtSetValues(w,arglist,n); 
  262. }
  263. /*
  264.  *  Delete a file structure
  265.  *  -----------------------
  266.  */
  267. static void FreeFile(file)
  268. WWWFile *file;
  269. {
  270.   XtFree((char *)file);
  271. }
  272. /*
  273.  *  Create a copy of a file structure
  274.  *  ---------------------------------
  275.  */
  276. static WWWFile *CopyFile(file)
  277. WWWFile *file;
  278. {
  279.   WWWFile *new = XtNew(WWWFile);
  280.   
  281.   *new = *file;
  282.   return new; 
  283. }
  284. static int CompareFile(file1,file2)
  285. WWWFile *file1;
  286. WWWFile *file2;
  287. {
  288.   return memcmp(file1,file2,sizeof(WWWFile));
  289. }
  290. /*
  291.  * Find (or create) a node
  292.  * -----------------------
  293.  */ 
  294.  
  295. static WWWNode *WWWCreateNode(file,parent)
  296. WWWFile *file;
  297. WWWNode *parent;
  298. {
  299.   int hashid = WWWHash(file);
  300.   WWWNode *a = HashTable[hashid]; 
  301.  
  302.   for (; a != NULL; a = a->hashclash) if (!CompareFile(a->file,file)) return a;
  303.  
  304.   a = XtNew(WWWNode);
  305.         
  306.   a->file = CopyFile(file);
  307.  
  308.   a->parent = parent ? parent : a;
  309.   a->prev = NULL; 
  310.   a->next = NULL;
  311.   a->up   = NULL;
  312.   a->down = NULL;
  313.   a->chain= NULL;
  314.   a->visited = FALSE;
  315.  
  316.   a->widgets = NULL;
  317.   a->num_widgets = 0;
  318.   a->alloc_widgets = 0;
  319.    
  320.   a->hashclash = HashTable[hashid];
  321.   HashTable[hashid] = a;
  322.  
  323.   return a; 
  324. }
  325. /*
  326.  * Find (or create) a node and if necessary its parent
  327.  * ---------------------------------------------------
  328.  */ 
  329. static WWWNode *WWWCreateNodeAndParent(file)
  330. WWWFile *file;
  331. {
  332.    WWWNode *parent;
  333.  
  334.    if (file->anchor) 
  335.      {
  336.        XrmQuark temp = file->anchor;
  337.        file->anchor = NULL;      
  338.        parent = WWWCreateNode(file,NULL);
  339.        file->anchor = temp;
  340.      }
  341.    else parent = NULL;
  342.        
  343.    return WWWCreateNode(file,parent);
  344. }
  345. /*
  346.  * Mark a node as visited
  347.  * ----------------------
  348.  */
  349. WWWVisitNode(node)
  350. WWWNode *node;
  351. {
  352.   if (!node->visited)
  353.     {
  354.       WWWNode *src = node->up;  
  355.  
  356.       for ( ; src != NULL; src = src->chain)
  357.         {
  358.            WidgetList w = src->widgets;
  359.            int nw = src->num_widgets; 
  360.            for (; nw-- > 0; w++) WWWBeenThere(*w);
  361.         }
  362.       node->visited = TRUE;
  363.      } 
  364. }
  365. static void WWWDetachWidgetFromNode(w,node)
  366. Widget w;
  367. WWWNode *node;
  368. {
  369.   int i;
  370.   for (i=0 ; i < node->num_widgets; i++)
  371.     if (node->widgets[i] == w) node->widgets[i] = node->widgets[--node->num_widgets];
  372. }
  373. static void WWWAttachWidgetToNode(node,w)
  374. WWWNode *node;
  375. Widget w;
  376. {
  377.    if (node->num_widgets == node->alloc_widgets) 
  378.      node->widgets = (Widget *) XtRealloc((char *) node->widgets, (node->alloc_widgets += 5) * sizeof(Widget));
  379.    node->widgets[node->num_widgets++] = w;
  380.    XtAddCallback(w,XtNdestroyCallback,WWWDetachWidgetFromNode,(XtPointer)node);
  381. }
  382. /*
  383.  * Provides buffering for the TCP/IP packets
  384.  * -----------------------------------------
  385.  */
  386. static char GetCharacter(data)
  387. DataSource *data;
  388. {
  389.   static char response[1024];
  390.  
  391.   if (data->nleft == 0)
  392.     {
  393.       data->nleft = socket_read(data->socket,response,sizeof(response));
  394.       data->next = response;
  395.     }
  396.   if (data->nleft-- > 0) return *(data->next++); 
  397.  
  398.   return '\0'; 
  399. }
  400. static char GetFileCharacter(f)
  401. FILE **f;
  402. {
  403.     int n =  getc(*f);
  404.     return (n==EOF?0:(char)n);
  405. }
  406. /*
  407.  * Fetch the local document
  408.  * ------------------------
  409.  */
  410.  
  411. static Widget WWWFetchDocumentLOCAL(w,file)
  412. Widget w;
  413. WWWFile *file;
  414. {
  415.   Widget result;
  416.   char *name = XrmQuarkToString(file->file); 
  417.  
  418.   FILE *f = fopen(name,"r");
  419.   if (f == NULL)   
  420.     {
  421.       char command[256]; 
  422.       sprintf(command,"<h2>Error:</h2>Cannot open file %s<p>For more information see <a href=%sfile_open_failed.html>help</a>.",
  423.               name,appResources.help);
  424.       return SGMLHyperSetText(w,command);
  425.     }  
  426.  
  427.   result = SGMLHyperLoadText(w,GetFileCharacter,&f);     
  428.   
  429.   fclose(f);
  430.   return result;
  431. }  
  432. /*
  433.  * Fetch the document using TCP/IP
  434.  * -------------------------------
  435.  */
  436.  
  437. static Widget WWWFetchDocumentHTTP(w,file)
  438. Widget w;
  439. WWWFile *file;
  440. {
  441.   struct sockaddr_in server;
  442.   int n, s, status;
  443.   char command[256]; 
  444.   char *node = XrmQuarkToString(file->node);
  445.   struct hostent *hp;
  446.   DataSource data;
  447.   Widget result;
  448.  
  449.   hp = gethostbyname(node);
  450.   if (hp == 0)
  451.     {
  452.       sprintf(command,"<h2>Error:</h2>Host %s unknown<p>For more information see <a href=%sunknown_host.html>help</a>.",
  453.               node,appResources.help);
  454.       return SGMLHyperSetText(w,command);
  455.     }
  456.   server.sin_family = AF_INET;
  457.   server.sin_port = htons(file->port?file->port:appResources.default_HTTP_port);
  458.   bcopy(hp->h_addr,&server.sin_addr, hp->h_length);
  459.   
  460.   s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  461.   status = connect(s,&server,sizeof(server));
  462.   
  463.   if (status<0) 
  464.     {
  465.       sprintf(command,"<h2>Error:</h2>Cannot connect to %s port %d<p>For more information see <a href=%scannot_connect.html>help</a>.",
  466.               node,file->port,appResources.help);
  467.       socket_close(s);
  468.       return SGMLHyperSetText(w,command);
  469.     }
  470.   
  471.   strcpy(command,"GET ");
  472.   strcat(command,XrmQuarkToString(file->file)); 
  473.   strcat(command, "\r\n");
  474.  
  475.   socket_write(s,command,strlen(command));
  476.   
  477.   data.socket = s;
  478.   data.nleft = 0;
  479.   
  480.   result = SGMLHyperLoadText(w,GetCharacter,&data);     
  481.   
  482.   socket_close(s);
  483.   return result;
  484. }  
  485. /*
  486.  * Fetch the document using appropriate protocol
  487.  * ---------------------------------------------
  488.  */
  489.  
  490. static Widget WWWFetchDocument(w,file)
  491. Widget w;
  492. WWWFile *file;
  493. {
  494.  
  495.   if      (file->protocol == httpProtocol ) return WWWFetchDocumentHTTP(w,file);
  496.   else if (file->protocol == localProtocol) return WWWFetchDocumentLOCAL(w,file);
  497.   else 
  498.     {
  499.       WWWFile actual;   
  500.       char p[256]; 
  501.  
  502.       *p = '/';
  503.       WWWAsciiFile(p+1,file);
  504.       
  505.       actual.protocol = WWWGateway->protocol;
  506.       actual.node     = WWWGateway->node;
  507.       actual.port     = WWWGateway->port;
  508.       actual.file = XrmStringToQuark(p); 
  509.       actual.keyword = NULL;
  510.       actual.anchor = NULL; 
  511.       
  512.       return WWWFetchDocumentHTTP(w,&actual);
  513.     }
  514. }  
  515. static void WWWZapNode(w,node)
  516. Widget w;
  517. WWWNode *node;
  518. {
  519.    int n=0;
  520. /* 
  521.  * Remove a cached document
  522.  */
  523.  
  524.   node = node->parent;
  525.   
  526.   for (n = 0; n < node->num_widgets; n++)
  527.     {
  528.       Widget t = node->widgets[n];
  529.       if (SGMLIsCompositeText(t) && XtParent(t) == w)
  530.         {     
  531.            WWWDetachWidgetFromNode(t,node);  
  532.            XtDestroyWidget(t);
  533.            break;   
  534.         }
  535.     }    
  536. }
  537. /*
  538.  * Display a new node in a widget
  539.  * ------------------------------
  540.  */ 
  541. static void WWWDisplayNode(w,node)
  542. Widget w;
  543. WWWNode *node;
  544. {
  545.    Widget new;
  546.    int n=0;
  547. /*
  548.  *  The document may already be cached in the widget?
  549.  */    
  550.   
  551.   for (n = 0; n < node->num_widgets; n++)
  552.     {
  553.       Widget t = node->widgets[n];
  554.       if (SGMLIsCompositeText(t) && XtParent(t) == w)
  555.         {     
  556.            SGMLHyperManageChild(t);
  557.            return;   
  558.         }
  559.     }    
  560. /*
  561.  *  Otherwise we have to fetch it.
  562.  */
  563.  
  564.   nextid = 0;
  565.   lastnode = NULL;
  566.   parent = node;
  567.  
  568.   new = WWWFetchDocument(w,node->file);
  569.   WWWVisitNode(node);
  570.   SGMLHyperManageChild(new);
  571.   WWWAttachWidgetToNode(node,new);
  572. }
  573. /*
  574.  *  parse a character file specification to create a file structure
  575.  * ----------------------------------------------------------------
  576.  */  
  577. static WWWFile *ParseFile(infile,def)
  578. char *infile;
  579. WWWFile *def; 
  580. {
  581.   char *node, *oldfile, *newfile, *anchor, *protocol;
  582.   char *directory, *port;
  583.   WWWFile *result = CopyFile(def);
  584.   char *file = XtNewString(infile); 
  585.   char *orig = file;
  586.    
  587.   result->anchor = NULL; /* NOT inherited from default */
  588.  
  589.   node = strstr(file,"/");
  590.   protocol = strchr(file,':');
  591.   if (protocol && (protocol < node || node == 0)) 
  592.     {
  593.       *protocol = '\0';
  594.       result->protocol = XrmStringToQuark(file);
  595.       if (result->protocol != def->protocol)
  596.         {    
  597.           result->node = NULL;
  598.           result->port = 0;
  599.         }  
  600.       file = protocol + 1;
  601.     } 
  602.   else protocol = NULL; 
  603.     
  604.   if (strncmp(file,"//",2)) 
  605.     { 
  606.       if (*file == '/' || protocol) 
  607.         {
  608.           result->file = XrmStringToQuark(file); 
  609.         }
  610.       else
  611.         {
  612.           Boolean absolute;
  613.  
  614.           oldfile = XtNewString(XrmQuarkToString(result->file));
  615.           absolute = (*oldfile == '/');
  616.  
  617.           if (anchor = strchr(file,'#')) 
  618.           {
  619.             *anchor++ = '\0';
  620.             result->anchor = XrmStringToQuark(anchor);
  621.           }
  622.  
  623.           for (;*file;file += 3)
  624.             {
  625.               char *p = strrchr(oldfile,'/'); 
  626.               if (!p)  p = oldfile; 
  627.               *p = '\0';
  628.               if (strncmp(file,"../",3)) break;
  629.             }
  630.           newfile = strcpy((char *) XtMalloc(strlen(oldfile) + strlen(file) + 2),oldfile);
  631.           if ((absolute || *oldfile) && *file)strcat(newfile,"/");
  632.           strcat(newfile,file);
  633.           
  634.           result->file = XrmStringToQuark(newfile);
  635.           XtFree(newfile);
  636.           XtFree(oldfile);
  637.         }
  638.     }
  639.   else
  640.     {
  641.       char *p;
  642.  
  643.       node = file + 2;
  644.      
  645.       directory = strchr(node,'/');  
  646.       if (directory) *(directory) = '\0';
  647.  
  648.       port = strchr(node,':');
  649.       if (port)
  650.         {
  651.           *(port++) = '\0';
  652.           result->port = atoi(port);   
  653.         }
  654.  
  655.       for (p=node; *p != '\0'; p++) if (isupper(*p)) *p = tolower(*p);  
  656.       result->node = XrmStringToQuark(node);
  657.  
  658.       if (directory)
  659.         {
  660.           *(directory) = '/';
  661.  
  662.           if (anchor = strchr(directory,'#')) 
  663.             {
  664.               *anchor++ = '\0';
  665.               result->anchor = XrmStringToQuark(anchor);
  666.             }
  667.         }
  668.       result->file = XrmStringToQuark(directory); 
  669.       
  670.     }
  671.  
  672.   XtFree(orig);
  673.   return result;
  674. }
  675. static void WWWGet(ww,node)
  676. Widget ww;
  677. WWWNode *node;
  678. {
  679.   WWWLink *link;
  680.   
  681.   WWWDisplayNode(ww,node->parent); 
  682.   WWWToLink = node;
  683.    
  684.   if (node != node->parent) 
  685.     {
  686.        WidgetList w = node->widgets;
  687.        int nw = node->num_widgets; 
  688.        for (; nw-- > 0; w++) 
  689.          {
  690.             Widget p;
  691.             for (p = *w; p != NULL; p = XtParent(p)) 
  692.               if (p == ww) { SGMLHyperShowObject(ww,*w); return; }
  693.          }
  694.     }
  695.   else SGMLHyperShowObject(ww,NULL);
  696. }
  697. static void WWWDeleteHistory(list)
  698. List *list;
  699. {
  700.   ListItem *item = MidasFindItemInListPos(list,0);
  701.   if (item) MidasRemoveItemFromList(list,item);
  702. }
  703. static void WWWAddHistory(list,title)
  704. List *list;
  705. char *title;
  706. {
  707.   ListItem *item;
  708.   WWWLink *link = XtNew(WWWLink);
  709.   link->from = (WWWFromLink == DEADNODE) ? NULL : WWWFromLink;
  710.   link->to = WWWToLink;
  711.  
  712.   if (WWWFromLink == DEADNODE) MidasEmptyList(list);
  713.   if (WWWFromLink)
  714.     {
  715.       item = MidasAddItemToListPos(list,title,0);
  716.       item->Pointer = (XtPointer) link; 
  717.     }   
  718.  
  719.   WWWFromLink = DEADNODE;
  720.   WWWToLink = NULL;
  721. }
  722. static void WWWLinkHistory(node)
  723. WWWNode *node;
  724. {
  725.   WWWFromLink = node;
  726. }
  727. static void WWWPut(w,stuff)
  728. Widget w;
  729. char *stuff;
  730. {
  731.   Widget t = SGMLHyperSetText(w,stuff);
  732.   SGMLHyperManageChild(t); 
  733. }
  734. static void WWWDump(w,file)
  735. Widget w;
  736. char *file;
  737. {
  738.   char *dump;
  739.   FILE *out = fopen(file,"w");
  740.   if (out==NULL) MidasError("Could not open file %s",file);
  741.  
  742.   dump = SGMLHyperGetText(w,TRUE);
  743.   fputs(dump,out);
  744.   fclose(out); 
  745.   XtFree(dump);
  746. }
  747. /*
  748.  *  Called when a new anchor is created
  749.  *  ----------------------------------- 
  750.  */
  751. static void WWWCreateAnchor(w,doc)
  752. Widget w;
  753. WWWFile *doc;
  754. {
  755.   char *href, *name, buffer[12];
  756.   WWWNode *src  = NULL;
  757.   WWWNode *dest = NULL;
  758.   WWWFile *here = CopyFile(doc); 
  759.  
  760.   Arg arglist[10];
  761.   int n=0;
  762.   
  763.   XtSetArg(arglist[n],SGMLNhref,&href); n++;
  764.   XtSetArg(arglist[n],SGMLNname,&name); n++;
  765.   XtGetValues(w,arglist,n); 
  766.  
  767.   /*
  768.    *  Create a source node, if the node has no name then make
  769.    *  one up.
  770.    */
  771.  
  772.   if (!name || !(*name))
  773.     {
  774.       name = buffer;
  775.       sprintf(buffer,"@@%d",nextid++);  
  776.     } 
  777.  
  778.   here->anchor = XrmStringToQuark(name); 
  779.   
  780.   src = WWWCreateNode(here,parent);
  781.   FreeFile(here);
  782.     
  783.   if (lastnode) lastnode->next = src; 
  784.   src->prev = lastnode;
  785.   lastnode = src; 
  786.   WWWAttachWidgetToNode(src,w);
  787.  
  788.   n=0;
  789.   XtSetArg(arglist[n],SGMLNuserdata,(XtPointer) src); n++;
  790.   XtSetValues(w,arglist,n);
  791.   
  792.   /*
  793.    * If this node points somewhere then create a destination node
  794.    */  
  795.  
  796.   if (href && *href)
  797.     { 
  798.       WWWNode *p;  
  799.       here = ParseFile(href,doc);
  800.  
  801.       dest = WWWCreateNodeAndParent(here);
  802.       FreeFile(here); 
  803.  
  804.       src->down = dest;
  805.  
  806.       p = dest->up; 
  807.       for (; p != NULL; p  = p->chain) if (p==src) break;
  808.       if (p == NULL) 
  809.         {
  810.           src->chain = dest->up; 
  811.           dest->up = src;
  812.         } 
  813.       if (dest->visited) WWWBeenThere(w);
  814.     }
  815. }
  816. /*
  817.  * It should be possible to do this directly from MIDAS so this routine
  818.  * should go away as soon as it actually is.
  819.  */ 
  820. static void WWWCopyBackgroundColor(src,dest)
  821. Widget src;
  822. Widget dest;
  823.   Pixel bg;
  824.   Arg arglist[1];
  825.  
  826.   XtSetArg(arglist[0],XmNbackground,&bg);
  827.   XtGetValues(src,arglist,1);
  828.   XtSetArg(arglist[0],XmNbackground,bg);
  829.   XtSetValues(dest,arglist,1);
  830. }
  831. static MidasOperand WWWSource(w)
  832. Widget w;
  833. {
  834.   MidasOperand Temp;
  835.   char *dump = SGMLHyperGetText(w,TRUE);
  836.  
  837.   Temp.Value.P = dump;
  838.   Temp.Dynamic = TRUE;
  839.   Temp.Type = MString;
  840.   
  841.   return Temp; 
  842. }
  843. static MidasOperand WWWBack(list)
  844. List *list;
  845. {
  846.   MidasOperand Temp;
  847.  
  848.   ListItem *item = MidasFindItemInListPos(list,0);
  849.   WWWLink *link = (WWWLink *) item?item->Pointer:NULL;
  850.   Temp.Value.P = link ? (XtPointer) link->from : NULL;
  851.   
  852.   Temp.Dynamic = FALSE;
  853.   Temp.Type = "WWWNode";
  854.   
  855.   return Temp;
  856. }
  857. static MidasOperand WWWPrev(node)
  858. WWWNode *node;
  859. {
  860.   MidasOperand Temp;
  861.  
  862.   Temp.Value.P = node ? (XtPointer) node->prev : NULL;
  863.   Temp.Dynamic = FALSE;
  864.   Temp.Type = "WWWNode";
  865.   
  866.   return Temp; 
  867.  
  868. }
  869. static MidasOperand WWWNext(node)
  870. WWWNode *node;
  871. {
  872.   MidasOperand Temp;
  873.  
  874.   Temp.Value.P = node ? (XtPointer) node->next : NULL;
  875.   Temp.Dynamic = FALSE;
  876.   Temp.Type = "WWWNode";
  877.   
  878.   return Temp; 
  879.  
  880. }
  881. static MidasOperand WWWDest(node)
  882. WWWNode *node;
  883. {
  884.   MidasOperand Temp;
  885.  
  886.   Temp.Value.P = node ? (XtPointer) node->down : NULL;
  887.   Temp.Dynamic = FALSE;
  888.   Temp.Type = "WWWNode";
  889.   
  890.   return Temp; 
  891.  
  892. }
  893. static MidasOperand WWWGetNode(w)
  894. Widget w;
  895. {
  896.   MidasOperand Temp;
  897.   Arg arglist[10];
  898.   int n=0;
  899.   
  900.   XtSetArg(arglist[n],SGMLNuserdata,&Temp.Value.P); n++;
  901.   XtGetValues(w,arglist,n);
  902.  
  903.   Temp.Dynamic = FALSE;
  904.   Temp.Type = "WWWNode";
  905.   
  906.   return Temp; 
  907.  
  908. }
  909. static MidasOperand WWWParse(file,def)
  910. char *file;
  911. WWWFile *def;
  912. {
  913.   MidasOperand Temp;
  914.   
  915.   WWWFile *pfile = ParseFile(file,def);
  916.  
  917.   Temp.Value.P = (XtPointer) pfile;
  918.   Temp.Dynamic = TRUE;
  919.   Temp.Type = "WWWFile";
  920.        
  921.   return Temp;
  922. }
  923.  
  924. /* 
  925.  *  Converters
  926.  *  ----------
  927.  */
  928. static Boolean WWWConvertStringFile(In,Out)
  929. MidasOperand *In;
  930. MidasOperand *Out;  
  931.   WWWFile *pfile = ParseFile(In->Value.P,&WWWFileDefault);  
  932.  
  933.   Out->Value.P = (XtPointer) pfile;
  934.   Out->Dynamic = TRUE;
  935.        
  936.   return TRUE;
  937. }
  938. static Boolean WWWConvertStringNode(In,Out)
  939. MidasOperand *In;
  940. MidasOperand *Out;  
  941.   WWWFile *pfile = ParseFile(In->Value.P,&WWWFileDefault);  
  942.   WWWNode *node = WWWCreateNodeAndParent(pfile);
  943.   
  944.   FreeFile(pfile); 
  945.  
  946.   Out->Value.P = (XtPointer) node;
  947.   Out->Dynamic = FALSE;
  948.        
  949.   return TRUE;
  950. }
  951. static Boolean WWWConvertFileNode(In,Out)
  952. MidasOperand *In;
  953. MidasOperand *Out;  
  954.   if (In->Value.P)
  955.     {
  956.       WWWNode *node = WWWCreateNodeAndParent((WWWFile *) In->Value.P);  
  957.       Out->Value.P = (XtPointer) node;
  958.     }
  959.   else Out->Value.P = NULL;   
  960.   Out->Dynamic = FALSE;
  961.        
  962.   return TRUE;
  963. }
  964. static Boolean WWWConvertNodeFile(In,Out)
  965. MidasOperand *In;
  966. MidasOperand *Out;  
  967.   WWWNode *node = (WWWNode *) In->Value.P;
  968.  
  969.   Out->Value.P = node ? (XtPointer) node->file : NULL;
  970.   Out->Dynamic = FALSE;
  971.        
  972.   return TRUE;
  973. }
  974. static Boolean WWWConvertFileString(In,Out)
  975. MidasOperand *In;
  976. MidasOperand *Out;
  977. {
  978.   char *p = (char *) XtMalloc(256); /* BUG */
  979.   
  980.   WWWFile *pfile = (WWWFile *) In->Value.P;
  981.   WWWAsciiFile(p,pfile);  
  982.  
  983.   Out->Value.P = (XtPointer) p;
  984.   Out->Dynamic = TRUE;
  985.        
  986.   return TRUE;
  987. }
  988. static void WWWSetGateway(gateway)
  989. char *gateway;
  990. {
  991.   WWWGateway = ParseFile(gateway,&WWWFileDefault);
  992. }
  993. static void WWWInit(shell)
  994. Widget shell;
  995. {
  996.   XtGetApplicationResources(shell,(XtPointer) &appResources,resources,XtNumber(resources),NULL,0);
  997. }
  998. /*
  999.  * Initialization
  1000.  */ 
  1001. void WWWMidasInit(argc,argv)
  1002. int argc;
  1003. char *argv[];
  1004. {
  1005.   int i;
  1006.   
  1007.   for (i=0; i < HASHSIZE; i++) HashTable[i] = NULL; 
  1008.  
  1009.   localProtocol = XrmStringToQuark("local");
  1010.   httpProtocol = XrmStringToQuark("http");
  1011.  
  1012.   WWWFileDefault.protocol = httpProtocol;
  1013.   WWWFileDefault.port   = 0;
  1014.   WWWFileDefault.node   = NULL; 
  1015.   WWWFileDefault.file   = NULL; 
  1016.   WWWFileDefault.anchor = NULL; 
  1017.  
  1018. /*
  1019.  * MIDAS BUG confusion between name and String
  1020.  */
  1021.  
  1022.   MidasDeclareConverter("String","WWWFile", WWWConvertStringFile);
  1023.   MidasDeclareConverter("name","WWWFile", WWWConvertStringFile);
  1024.   MidasDeclareConverter("String","WWWNode", WWWConvertStringNode);
  1025.   MidasDeclareConverter("name","WWWNode", WWWConvertStringNode);
  1026.   MidasDeclareConverter("WWWFile","String", WWWConvertFileString);
  1027.   MidasDeclareConverter("WWWFile","name", WWWConvertFileString);
  1028.   MidasDeclareConverter("WWWFile","WWWNode",WWWConvertFileNode);
  1029.   MidasDeclareConverter("WWWNode","WWWFile",WWWConvertNodeFile);
  1030.   
  1031.  
  1032.   MidasDeclareVerb("WWW HASH DUMP"                ,WWWHashDump);
  1033.   MidasDeclareVerb("WWW INIT Widget"              ,WWWInit);
  1034.   MidasDeclareVerb("WWW SET GATEWAY name"         ,WWWSetGateway);
  1035.   MidasDeclareVerb("WWW DUMP Widget name"         ,WWWDump); 
  1036.   MidasDeclareVerb("WWW ADD HISTORY list name"    ,WWWAddHistory); 
  1037.   MidasDeclareVerb("WWW DELETE HISTORY list"      ,WWWDeleteHistory); 
  1038.   MidasDeclareVerb("WWW GET Widget WWWNode"       ,WWWGet); 
  1039.   MidasDeclareVerb("WWW ZAP Widget WWWNode"       ,WWWZapNode); 
  1040.   MidasDeclareVerb("WWW LINK {WWWNode}"           ,WWWLinkHistory);
  1041.   MidasDeclareVerb("WWW PUT Widget name"          ,WWWPut); 
  1042.   MidasDeclareVerb("WWW ANCHOR Widget WWWFile"    ,WWWCreateAnchor); 
  1043.   MidasDeclareVerb("WWW COPYB Widget Widget"      ,WWWCopyBackgroundColor); 
  1044.  
  1045.   MidasDeclareFunction("WWWPARSE(name,WWWFile)"   ,WWWParse); 
  1046.   MidasDeclareFunction("WWWSOURCE(Widget)"        ,WWWSource); 
  1047.   MidasDeclareFunction("WWWBACK(list)"            ,WWWBack); 
  1048.   MidasDeclareFunction("WWWPREV(WWWNode)"         ,WWWPrev); 
  1049.   MidasDeclareFunction("WWWNEXT(WWWNode)"         ,WWWNext); 
  1050.   MidasDeclareFunction("WWWDEST(WWWNode)"         ,WWWDest); 
  1051.   MidasDeclareFunction("WWWNODE(Widget)"          ,WWWGetNode);
  1052. }
  1053.  
  1054. /* 
  1055.  * Main routine for MidasWWW
  1056.  */
  1057.  
  1058. int main(argc,argv)
  1059. int argc;
  1060. char *argv[];
  1061.   MidasInitialize(argc,argv);
  1062.   WWWMidasInit(argc,argv);
  1063.   MidasMainLoop();
  1064. }
  1065.